﻿#include "..\..\include\Server\IPLocator.h"

//IP字符串 -> IP数值
unsigned int CIPLocator::IpStringToInt(const char * ipStr)
{
	int t[4];
	unsigned int ipv;
	unsigned char * p=(unsigned char *)&ipv;
	sscanf(ipStr,"%d.%d.%d.%d",&t[0],&t[1],&t[2],&t[3]);
	p[0]=t[3]; p[1]=t[2]; p[2]=t[1]; p[3]=t[0];
	return ipv;
}
//IP数值 -> IP字符串
char * CIPLocator::IntToIpString(int ipv)
{
	unsigned char * p=(unsigned char *)&ipv;
	static char ipStr[sizeof("xxx.xxx.xxx.xxx")];
	sprintf(ipStr,"%d.%d.%d.%d",p[3],p[2],p[1],p[0]);
	return ipStr;
}
// 采用“二分法”搜索索引区, 定位IP索引记录位置
int CIPLocator::getIndexOffset(int fo, int lo, unsigned int ipv)
{
	int mo;    //中间偏移量
	unsigned int mv;    //中间值
	unsigned int fv,lv; //边界值
	unsigned int llv;   //边界末末值
	fseek(m_pFile,fo,SEEK_SET);
	fread(&fv,4,1,m_pFile);
	fseek(m_pFile,lo,SEEK_SET);
	fread(&lv,4,1,m_pFile);
	//临时作它用,末记录体偏移量
	fread(&mo,3,1,m_pFile); mo&=0xffffff;
	fseek(m_pFile,mo,SEEK_SET);
	fread(&llv,sizeof(int),1,m_pFile);
	//printf("%d %d %d %d %d %d %d \n",fo,lo,mo,ipv,fv,lv,llv);
	//边界检测处理
	if(ipv<fv)
		return -1;
	else if(ipv>llv)
		return -1;
	//使用"二分法"确定记录偏移量
	do
	{
		mo=fo+(lo-fo)/7/2*7;
		fseek(m_pFile,mo,SEEK_SET);
		fread(&mv,sizeof(int),1,m_pFile);
		if(ipv>=mv)
			fo=mo;
		else
			lo=mo;
		if(lo-fo==7)
			mo=lo=fo;
	} while(fo!=lo);

	return mo;
}
// 读取IP所在地字符串
char * CIPLocator::getString(char * strBuf)
{
	//byte Tag;
	//int Offset;
	//Tag=m_pFile.ReadByte();
	char tag;
	int so;
	fread(&tag,sizeof(char),1,m_pFile);

	if(tag==0x01)   // 重定向模式1: 城市信息随国家信息定向
	{
		fread(&so,3,1,m_pFile); so&=0xffffff;
		fseek(m_pFile,so,SEEK_SET);
		return getString(strBuf);
	}
	else if(tag==0x02)   // 重定向模式2: 城市信息没有随国家信息定向
	{
		fread(&so,3,1,m_pFile); so&=0xffffff;
		//记下文件当前读位置
		int tmo=ftell(m_pFile);
		fseek(m_pFile,so,SEEK_SET);
		getString(strBuf);
		fseek(m_pFile,tmo,SEEK_SET);
		return strBuf;
	}
	else   // 无重定向: 最简单模式
	{
		fseek(m_pFile,-1,SEEK_CUR);
		//读取字符串
		fread(strBuf,sizeof(char),STR_BUFF_SIZE,m_pFile);
		//修正文件指针
		fseek(m_pFile,strlen(strBuf)+1-STR_BUFF_SIZE,SEEK_CUR);
		return strBuf;
	}
}
//查询IP段和所在地
IpLocation CIPLocator::GetIpLocation(unsigned int ipv)
{
	int fo = 0, lo = 0;   //首末索引偏移量
	//fseek(m_pFile,1,SEEK_SET);
	fread(&fo,sizeof(int),1,m_pFile);
	fread(&lo,sizeof(int),1,m_pFile);
	//获取索引记录偏移量
	int rcOffset;
	rcOffset=getIndexOffset(fo,lo,ipv);
	fseek(m_pFile,rcOffset,SEEK_SET);
	IpLocation ipl;
	if(rcOffset>=0)
	{
		fseek(m_pFile,rcOffset,SEEK_SET);
		//读取开头IP值
		fread(&ipl.IpStart,sizeof(int),1,m_pFile);
		//转到记录体
		int ro;   //记录体偏移量
		fread(&ro,3,1,m_pFile); ro&=0xffffff;
		fseek(m_pFile,ro,SEEK_SET);
		//读取结尾IP值
		fread(&ipl.IpEnd,sizeof(int),1,m_pFile);
		char strBuf[STR_BUFF_SIZE];
		getString(strBuf);
		ipl.Country=new char[strlen(strBuf+1)];
		strcpy(ipl.Country,strBuf);
		getString(strBuf);
		ipl.City=new char[strlen(strBuf+1)];
		strcpy(ipl.City,strBuf);

		fseek(m_pFile, 1, SEEK_SET);
	}
	else
	{
		//没找到
		ipl.IpStart=0;
		ipl.IpEnd=0;
		ipl.Country="未知国家";
		ipl.City="未知地址";
	}

	return ipl;
}

bool CIPLocator::LoadLib(const char *lpPath)
{
	m_pFile = fopen(lpPath,"rb");
	if(!m_pFile)
	{
		throw "打开数据文件失败";
		return false;
	}

	return true;
}